package com.google.gac.masai.getit;

import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;

import android.app.SearchManager;
import android.content.ClipDescription;
import android.content.ContentProvider;
import android.content.ContentProvider.PipeDataWriter;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.text.TextUtils;
import android.util.Log;

public class DownloadLogProvider extends ContentProvider implements
		PipeDataWriter<Cursor> {
	// Used for debugging and logging
	private static final String TAG = "DownloadLogProvider";

	/**
	 * The database that the provider uses as its underlying data store
	 */
	private static final String DATABASE_NAME = "download_log.db";

	/**
	 * The database version
	 */
	private static final int DATABASE_VERSION = 2;

	/**
	 * A projection map used to select columns from the database
	 */
	private static HashMap<String, String> sLogsProjectionMap;

	/**
	 * Standard projection for the interesting columns of a normal log.
	 */
	private static final String[] READ_LOG_PROJECTION = new String[] {
			DownloadLog.Logs._ID, // Projection position 0, the log's id
			DownloadLog.Logs.COLUMN_NAME_TITLE, // Projectino position 1, the
												// log's title
			DownloadLog.Logs.COLUMN_NAME_URI, // Projection position 2, the
												// log's uri
			DownloadLog.Logs.COLUMN_NAME_TAG // Projection position 3, the log's
												// log
	};
	private static final int READ_LOG_TITLE_INDEX = 1;
	private static final int READ_LOG_URI_INDEX = 2;
	private static final int READ_LOG_TAG_INDEX = 3;

	/*
	 * Constants used by the Uri matcher to choose an action based on the
	 * pattern of the incoming URI
	 */
	// The incoming URI matches the logs URI pattern
	private static final int LOGS = 0;

	// The incoming URI matches the log ID URI pattern
	private static final int LOG_ID = 1;

	private static final int SEARCH_WORDS = 2;
	private static final int GET_WORD = 3;
	private static final int SEARCH_SUGGEST = 4;

	/**
	 * A UriMatcher instance
	 */
	private static final UriMatcher sUriMatcher;

	// Handle to a new DatabaseHelper.
	private DatabaseHelper mOpenHelper;

	/**
	 * A block that instantiates and sets static objects
	 */
	static {
		/*
		 * Creates and initializes the URI matcher
		 */
		// Create a new instance
		sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
		// to get definition
		sUriMatcher.addURI(DownloadLog.AUTHORITY, "logs", SEARCH_WORDS);
		sUriMatcher.addURI(DownloadLog.AUTHORITY, "logs/#", GET_WORD);
		// to get suggestions..
		sUriMatcher.addURI(DownloadLog.AUTHORITY,
				SearchManager.SUGGEST_URI_PATH_QUERY, SEARCH_SUGGEST);
		sUriMatcher.addURI(DownloadLog.AUTHORITY,
				SearchManager.SUGGEST_URI_PATH_QUERY + "/*", SEARCH_SUGGEST);
		// Add a pattern that routes URIs terminated with "logs" to a logS
		// operation
		sUriMatcher.addURI(DownloadLog.AUTHORITY, "logs", LOGS);

		// Add a pattern that routes URIs terminated with "logs" plus an
		// integer
		// to a log ID operation
		sUriMatcher.addURI(DownloadLog.AUTHORITY, "logs/#", LOG_ID);

		/*
		 * Creates and initializes a projection map that returns all columns
		 */

		// Creates a new projection map instance. The map returns a column name
		// given a string. The two are usually equal.
		sLogsProjectionMap = new HashMap<String, String>();

		// Maps the string "_ID" to the column name "_ID"
		sLogsProjectionMap.put(DownloadLog.Logs._ID, DownloadLog.Logs._ID);

		// Maps "title" to "title"
		sLogsProjectionMap.put(DownloadLog.Logs.COLUMN_NAME_TITLE,
				DownloadLog.Logs.COLUMN_NAME_TITLE);

		// Maps "uri" to "uri"
		sLogsProjectionMap.put(DownloadLog.Logs.COLUMN_NAME_URI,
				DownloadLog.Logs.COLUMN_NAME_URI);

		// Maps "TAG" to "tag"
		sLogsProjectionMap.put(DownloadLog.Logs.COLUMN_NAME_TAG,
				DownloadLog.Logs.COLUMN_NAME_TAG);

		// Maps "created" to "created"
		sLogsProjectionMap.put(DownloadLog.Logs.COLUMN_NAME_CREATE_DATE,
				DownloadLog.Logs.COLUMN_NAME_CREATE_DATE);

		// Maps "modified" to "modified"
		sLogsProjectionMap.put(DownloadLog.Logs.COLUMN_NAME_MODIFICATION_DATE,
				DownloadLog.Logs.COLUMN_NAME_MODIFICATION_DATE);

		sLogsProjectionMap.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID,
				SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID);

	}

	/**
	 * This class helps open, create, and upgrade the database file. Set to
	 * package visibility for testing purposes.
	 * 
	 */
	static class DatabaseHelper extends SQLiteOpenHelper {

		DatabaseHelper(Context context) {
			super(context, DATABASE_NAME, null, DATABASE_VERSION);
		}

		@Override
		public void onCreate(SQLiteDatabase db) {

			db.execSQL("CREATE TABLE " + DownloadLog.Logs.TABLE_NAME + " ("
					+ DownloadLog.Logs._ID + " INTEGER PRIMARY KEY,"
					+ DownloadLog.Logs.COLUMN_NAME_TITLE + " TEXT,"
					+ DownloadLog.Logs.COLUMN_NAME_URI + " TEXT,"
					+ DownloadLog.Logs.COLUMN_NAME_TAG + " TEXT,"
					+ DownloadLog.Logs.COLUMN_NAME_CREATE_DATE + " TEXT,"
					+ DownloadLog.Logs.COLUMN_NAME_MODIFICATION_DATE + " TEXT"
					+ ");");
		}

		/**
		 * 
		 * Demonstrates that the provider must consider what happens when the
		 * underlying datastore is changed. In this sample, the database is
		 * upgraded the database by destroying the existing data. A real
		 * application should upgrade the database in place.
		 */
		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			Log.w("SQLhelper", "Upgrading database from version " + oldVersion
					+ " to " + newVersion + ", which will destroy all old data");
			db.execSQL("DROP TABLE IF EXISTS logs");
			onCreate(db);
		}
	}

	/**
	 * Initializes the provider by creating a new DatabaseHelper. onCreate() is
	 * called automatically when Android creates the provider in response to a
	 * resolver request from a client.
	 */
	@Override
	public boolean onCreate() {
		// Creates a new helper object. Note that the database itself isn't
		// opened until something tries to access it, and it's only created if
		// it doesn't already exist.
		mOpenHelper = new DatabaseHelper(getContext());
		return true;
	}

	private Cursor query(String selection, String[] selectionArgs,
			String[] columns) {
		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
		qb.setTables(DownloadLog.Logs.TABLE_NAME);
		SQLiteDatabase db = mOpenHelper.getReadableDatabase();
		/*
		 * Performs the query. If no problems occur trying to read the database,
		 * then a Cursor object is returned; otherwise, the cursor variable
		 * contains null. If no records were selected, then the Cursor object is
		 * empty, and Cursor.getCount() returns 0.
		 */
		Cursor c = qb.query(db, // The database to query
				columns, // The columns to return from the query
				selection, // The columns for the where clause
				selectionArgs, // The values for the where clause
				null, // don't group the rows
				null, // don't filter by row groups
				DownloadLog.Logs.DEFAULT_SORT_ORDER // The sort order
				);
		return c;
	}

	/**
	 * This method is called when a client calls
	 * {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)}
	 * . Queries the database and returns a cursor containing the results.
	 * 
	 * @return A cursor containing the results of the query. The cursor exists
	 *         but is empty if the query returns no results or an exception
	 *         occurs.
	 * @throws IllegalArgumentException
	 *             if the incoming URI pattern is invalid.
	 */
	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
		qb.setTables(DownloadLog.Logs.TABLE_NAME);
		String query = uri.getLastPathSegment().toLowerCase();
		Log.d("DownloadLogProvider_QUERY", query);
		SQLiteDatabase db = mOpenHelper.getReadableDatabase();
		switch (sUriMatcher.match(uri)) {
		case LOGS:
			qb.setProjectionMap(sLogsProjectionMap);
			break;
		case LOG_ID:
			qb.setProjectionMap(sLogsProjectionMap);
			qb.appendWhere(DownloadLog.Logs._ID
					+ "="
					+ uri.getPathSegments().get(
							DownloadLog.Logs.LOG_ID_PATH_POSITION));
			break;
		case SEARCH_SUGGEST:
			Cursor returnCursor = db.query(DownloadLog.Logs.TABLE_NAME,
					new String[] { DownloadLog.Logs.COLUMN_NAME_TITLE,
							DownloadLog.Logs.COLUMN_NAME_TAG }, null, null,
					null, null, null);
			MatrixCursor matrixCursor = new MatrixCursor(new String[] { "_ID",
					SearchManager.SUGGEST_COLUMN_TEXT_1,
					SearchManager.SUGGEST_COLUMN_TEXT_2,
					SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID });

			returnCursor.moveToFirst();

			int id_index = returnCursor.getColumnIndex(DownloadLog.Logs._ID);
			int name_index = returnCursor
					.getColumnIndex(DownloadLog.Logs.COLUMN_NAME_TITLE);
			int tag_index = returnCursor
					.getColumnIndex(DownloadLog.Logs.COLUMN_NAME_TAG);
			int cnt = 0;
			ArrayList<String> tag_list = new ArrayList<String>();
			Iterator iter = tag_list.iterator();
			Boolean isContain = false;
			while (!returnCursor.isAfterLast()) {
				isContain = false;
				String temp = returnCursor.getString(name_index);
				if (temp.toLowerCase().startsWith(query)) {
					Log.d(TAG, "BY NAME " + returnCursor.getString(name_index));
					matrixCursor.addRow(new String[] {
							cnt + "",
							temp,
							"Open the File",
							"filename@"
									+ Integer.toString(returnCursor
											.getInt(name_index)) });
					cnt++;
				}
				temp = returnCursor.getString(tag_index);
				isContain = tag_list.contains(temp);
				if(!isContain){
					tag_list.add(temp);
				}
				if (temp.toLowerCase().startsWith(query) && !isContain) {
					Log.d(TAG, "BY TAG " + returnCursor.getString(tag_index));
					matrixCursor.addRow(new String[] {
							cnt + "",
							temp,
							"View this Tag",
							"tag@"
									+ Integer.toString(returnCursor
											.getInt(tag_index)) });
					cnt++;
				}

				returnCursor.moveToNext();
				
			}
			matrixCursor.moveToFirst();
			return (Cursor) matrixCursor;
		case SEARCH_WORDS:
			if (selectionArgs == null) {
				throw new IllegalArgumentException(
						"selectionArgs must be provided for the Uri: " + uri);
			}
			return search(selectionArgs[0]);
		case GET_WORD:
			return getWord(uri);
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);

		}

		String orderBy;

		if (TextUtils.isEmpty(sortOrder)) {
			orderBy = DownloadLog.Logs.DEFAULT_SORT_ORDER;
		} else {
			orderBy = sortOrder;
		}

		/*
		 * Performs the query. If no problems occur trying to read the database,
		 * then a Cursor object is returned; otherwise, the cursor variable
		 * contains null. If no records were selected, then the Cursor object is
		 * empty, and Cursor.getCount() returns 0.
		 */
		Cursor c = qb.query(db, // The database to query
				projection, // The columns to return from the query
				selection, // The columns for the where clause
				selectionArgs, // The values for the where clause
				null, // don't group the rows
				null, // don't filter by row groups
				orderBy // The sort order
				);

		// Tells the Cursor what URI to watch, so it knows when its source data
		// changes
		c.setNotificationUri(getContext().getContentResolver(), uri);
		return c;
	}

	private Cursor search(String query) {
		query = query.toLowerCase();
		String[] columns = new String[] { DownloadLog.Logs._ID,
				DownloadLog.Logs.COLUMN_NAME_TITLE, // 1
				DownloadLog.Logs.COLUMN_NAME_URI, // 2
		};
		String selection = DownloadLog.Logs.COLUMN_NAME_TITLE + " MATCH ?";
		String[] selectionArgs = new String[] { query + "*" };

		return query(selection, selectionArgs, columns);
	}

	private Cursor getWord(Uri uri) {
		String rowId = uri.getLastPathSegment();
		String[] columns = new String[] { DownloadLog.Logs.COLUMN_NAME_TITLE, // 1
				DownloadLog.Logs.COLUMN_NAME_URI, // 2
		};
		String selection = "rowid = ?";
		String[] selectionArgs = new String[] { rowId };
		return query(selection, selectionArgs, columns);
	}

	/**
	 * This is called when a client calls
	 * {@link android.content.ContentResolver#getType(Uri)}. Returns the MIME
	 * data type of the URI given as a parameter.
	 * 
	 * @param uri
	 *            The URI whose MIME type is desired.
	 * @return The MIME type of the URI.
	 * @throws IllegalArgumentException
	 *             if the incoming URI pattern is invalid.
	 */
	@Override
	public String getType(Uri uri) {
		/**
		 * Chooses the MIME type based on the incoming URI pattern
		 */
		switch (sUriMatcher.match(uri)) {

		// If the pattern is for logs or live folders, returns the general
		// content type.
		case LOGS:
			return DownloadLog.Logs.CONTENT_TYPE;

			// If the pattern is for log IDs, returns the log ID content type.
		case LOG_ID:
			return DownloadLog.Logs.CONTENT_ITEM_TYPE;

		case SEARCH_SUGGEST:
			return SearchManager.SUGGEST_MIME_TYPE;
			// If the URI pattern doesn't match any permitted patterns, throws
			// an exception.
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
	}

	/**
	 * This describes the MIME types that are supported for opening a log URI as
	 * a stream.
	 */
	static ClipDescription LOG_STREAM_TYPES = new ClipDescription(null,
			new String[] { ClipDescription.MIMETYPE_TEXT_PLAIN });

	/**
	 * Returns the types of available data streams. URIs to specific logs are
	 * supported. The application can convert such a log to a plain text stream.
	 * 
	 * @param uri
	 *            the URI to analyze
	 * @param mimeTypeFilter
	 *            The MIME type to check for. This method only returns a data
	 *            stream type for MIME types that match the filter. Currently,
	 *            only text/plain MIME types match.
	 * @return a data stream MIME type. Currently, only text/plan is returned.
	 * @throws IllegalArgumentException
	 *             if the URI pattern doesn't match any supported patterns.
	 */
	@Override
	public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
		/**
		 * Chooses the data stream type based on the incoming URI pattern.
		 */
		switch (sUriMatcher.match(uri)) {

		// If the pattern is for logs or live folders, return null. Data
		// streams are not
		// supported for this type of URI.
		case LOGS:
			return null;

			// If the pattern is for log IDs and the MIME filter is text/plain,
			// then return
			// text/plain
		case LOG_ID:
			return LOG_STREAM_TYPES.filterMimeTypes(mimeTypeFilter);

			// If the URI pattern doesn't match any permitted patterns, throws
			// an exception.
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
	}

	/**
	 * Returns a stream of data for each supported stream type. This method does
	 * a query on the incoming URI, then uses
	 * {@link android.content.ContentProvider#openPipeHelper(Uri, String, Bundle, Object, PipeDataWriter)}
	 * to start another thread in which to convert the data into a stream.
	 * 
	 * @param uri
	 *            The URI pattern that points to the data stream
	 * @param mimeTypeFilter
	 *            A String containing a MIME type. This method tries to get a
	 *            stream of data with this MIME type.
	 * @param opts
	 *            Additional options supplied by the caller. Can be interpreted
	 *            as desired by the content provider.
	 * @return AssetFileDescriptor A handle to the file.
	 * @throws FileNotFoundException
	 *             if there is no file associated with the incoming URI.
	 */
	@Override
	public AssetFileDescriptor openTypedAssetFile(Uri uri,
			String mimeTypeFilter, Bundle opts) throws FileNotFoundException {

		// Checks to see if the MIME type filter matches a supported MIME type.
		String[] mimeTypes = getStreamTypes(uri, mimeTypeFilter);

		// If the MIME type is supported
		if (mimeTypes != null) {

			// Retrieves the log for this URI. Uses the query method defined
			// for this provider,
			// rather than using the database query method.
			Cursor c = query(uri, // The URI of a log
					READ_LOG_PROJECTION, // Gets a projection containing the
											// log's ID, title,
											// and contents
					null, // No WHERE clause, get all matching records
					null, // Since there is no WHERE clause, no selection
							// criteria
					null // Use the default sort order (modification date,
							// descending
			);

			// If the query fails or the cursor is empty, stop
			if (c == null || !c.moveToFirst()) {

				// If the cursor is empty, simply close the cursor and return
				if (c != null) {
					c.close();
				}

				// If the cursor is null, throw an exception
				throw new FileNotFoundException("Unable to query " + uri);
			}

			// Start a new thread that pipes the stream data back to the caller.
			return new AssetFileDescriptor(openPipeHelper(uri, mimeTypes[0],
					opts, c, this), 0, AssetFileDescriptor.UNKNOWN_LENGTH);
		}

		// If the MIME type is not supported, return a read-only handle to the
		// file.
		return super.openTypedAssetFile(uri, mimeTypeFilter, opts);
	}

	/**
	 * Implementation of {@link android.content.ContentProvider.PipeDataWriter}
	 * to perform the actual work of converting the data in one of cursors to a
	 * stream of data for the client to read.
	 */
	// @Override
	public void writeDataToPipe(ParcelFileDescriptor output, Uri uri,
			String mimeType, Bundle opts, Cursor c) {
		
	}

	/**
	 * This is called when a client calls
	 * {@link android.content.ContentResolver#insert(Uri, ContentValues)}.
	 * Inserts a new row into the database. This method sets up default values
	 * for any columns that are not included in the incoming map. If rows were
	 * inserted, then listeners are notified of the change.
	 * 
	 * @return The row ID of the inserted row.
	 * @throws SQLException
	 *             if the insertion fails.
	 */
	@Override
	public Uri insert(Uri uri, ContentValues initialValues) {

		// Validates the incoming URI. Only the full provider URI is allowed for
		// inserts.
		if (sUriMatcher.match(uri) != LOGS) {
			throw new IllegalArgumentException("Unknown URI " + uri);
		}

		// A map to hold the new record's values.
		ContentValues values;

		// If the incoming values map is not null, uses it for the new values.
		if (initialValues != null) {
			values = new ContentValues(initialValues);

		} else {
			// Otherwise, create a new value map
			values = new ContentValues();
		}

		// Gets the current system time in milliseconds
		Calendar date = Calendar.getInstance();
		;

		String now = (date.get(Calendar.YEAR) + "/" + date.get(Calendar.MONTH)
				+ "/" + date.get(Calendar.DAY_OF_MONTH) + " "
				+ date.get(Calendar.HOUR_OF_DAY) + ":" + date
				.get(Calendar.MINUTE));
		// Long now = Long.valueOf(System.currentTimeMillis());

		// If the values map doesn't contain the creation date, sets the value
		// to the current time.
		if (values.containsKey(DownloadLog.Logs.COLUMN_NAME_CREATE_DATE) == false) {
			values.put(DownloadLog.Logs.COLUMN_NAME_CREATE_DATE, now);
		}

		// If the values map doesn't contain the modification date, sets the
		// value to the current
		// time.
		if (values.containsKey(DownloadLog.Logs.COLUMN_NAME_MODIFICATION_DATE) == false) {
			values.put(DownloadLog.Logs.COLUMN_NAME_MODIFICATION_DATE, now);
		}

		// If the values map doesn't contain a title, sets the value to the
		// default title.
		if (values.containsKey(DownloadLog.Logs.COLUMN_NAME_TITLE) == false) {
			Resources r = Resources.getSystem();
			// ToDo check this part
			values.put(DownloadLog.Logs.COLUMN_NAME_TITLE,
					r.getString(android.R.string.untitled));
		}

		// If the values map doesn't contain log text, sets the value to an
		// empty string.
		if (values.containsKey(DownloadLog.Logs.COLUMN_NAME_TAG) == false) {
			values.put(DownloadLog.Logs.COLUMN_NAME_TAG, "");
		}

		// If the values map doesn't contain log text, sets the value to an
		// empty string.
		if (values.containsKey(DownloadLog.Logs.COLUMN_NAME_URI) == false) {
			values.put(DownloadLog.Logs.COLUMN_NAME_URI, "Can't Find");
		}

		// Opens the database object in "write" mode.
		SQLiteDatabase db = mOpenHelper.getWritableDatabase();

		// Performs the insert and returns the ID of the new log.
		long rowId = db.insert(DownloadLog.Logs.TABLE_NAME, // The table to
															// insert into.
				DownloadLog.Logs.COLUMN_NAME_TAG, // A hack, SQLite sets this
													// column value to null
				// if values is empty.
				values // A map of column names, and the values to insert
						// into the columns.
				);

		// If the insert succeeded, the row ID exists.
		if (rowId > 0) {
			// Creates a URI with the log ID pattern and the new row ID appended
			// to it.
			Uri logUri = ContentUris.withAppendedId(
					DownloadLog.Logs.CONTENT_ID_URI_BASE, rowId);

			// Notifies observers registered against this provider that the data
			// changed.
			getContext().getContentResolver().notifyChange(logUri, null);
			return logUri;
		}
		// If the insert didn't succeed, then the rowID is <= 0. Throws an
		// exception.
		throw new SQLException("Failed to insert row into " + uri);
	}

	/**
	 * This is called when a client calls
	 * {@link android.content.ContentResolver#delete(Uri, String, String[])}.
	 * Deletes records from the database. If the incoming URI matches the log ID
	 * URI pattern, this method deletes the one record specified by the ID in
	 * the URI. Otherwise, it deletes a a set of records. The record or records
	 * must also match the input selection criteria specified by where and
	 * whereArgs.
	 * 
	 * If rows were deleted, then listeners are notified of the change.
	 * 
	 * @return If a "where" clause is used, the number of rows affected is
	 *         returned, otherwise 0 is returned. To delete all rows and get a
	 *         row count, use "1" as the where clause.
	 * @throws IllegalArgumentException
	 *             if the incoming URI pattern is invalid.
	 */
	@Override
	public int delete(Uri uri, String where, String[] whereArgs) {

		// Opens the database object in "write" mode.
		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		String finalWhere;

		int count;

		// Does the delete based on the incoming URI pattern.
		switch (sUriMatcher.match(uri)) {

		// If the incoming pattern matches the general pattern for logs, does a
		// delete
		// based on the incoming "where" columns and arguments.
		case LOGS:
			count = db.delete(DownloadLog.Logs.TABLE_NAME, // The database table
															// name
					where, // The incoming where clause column names
					whereArgs // The incoming where clause values
					);
			break;

		// If the incoming URI matches a single log ID, does the delete based
		// on the
		// incoming data, but modifies the where clause to restrict it to the
		// particular log ID.
		case LOG_ID:
			/*
			 * Starts a final WHERE clause by restricting it to the desired log
			 * ID.
			 */
			finalWhere = DownloadLog.Logs._ID + // The ID column name
					" = " + // test for equality
					uri.getPathSegments(). // the incoming log ID
							get(DownloadLog.Logs.LOG_ID_PATH_POSITION);

			// If there were additional selection criteria, append them to the
			// final
			// WHERE clause
			if (where != null) {
				finalWhere = finalWhere + " AND " + where;
			}

			// Performs the delete.
			count = db.delete(DownloadLog.Logs.TABLE_NAME, // The database table
															// name.
					finalWhere, // The final WHERE clause
					whereArgs // The incoming where clause values.
					);
			break;

		// If the incoming pattern is invalid, throws an exception.
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
		/*
		 * Gets a handle to the content resolver object for the current context,
		 * and notifies it that the incoming URI changed. The object passes this
		 * along to the resolver framework, and observers that have registered
		 * themselves for the provider are notified.
		 */
		getContext().getContentResolver().notifyChange(uri, null);

		// Returns the number of rows deleted.
		return count;
	}

	/**
	 * This is called when a client calls
	 * {@link android.content.ContentResolver#update(Uri,ContentValues,String,String[])}
	 * Updates records in the database. The column names specified by the keys
	 * in the values map are updated with new data specified by the values in
	 * the map. If the incoming URI matches the log ID URI pattern, then the
	 * method updates the one record specified by the ID in the URI; otherwise,
	 * it updates a set of records. The record or records must match the input
	 * selection criteria specified by where and whereArgs. If rows were
	 * updated, then listeners are notified of the change.
	 * 
	 * @param uri
	 *            The URI pattern to match and update.
	 * @param values
	 *            A map of column names (keys) and new values (values).
	 * @param where
	 *            An SQL "WHERE" clause that selects records based on their
	 *            column values. If this is null, then all records that match
	 *            the URI pattern are selected.
	 * @param whereArgs
	 *            An array of selection criteria. If the "where" param contains
	 *            value placeholders ("?"), then each placeholder is replaced by
	 *            the corresponding element in the array.
	 * @return The number of rows updated.
	 * @throws IllegalArgumentException
	 *             if the incoming URI pattern is invalid.
	 */
	@Override
	public int update(Uri uri, ContentValues values, String where,
			String[] whereArgs) {

		// Opens the database object in "write" mode.
		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		int count;
		String finalWhere;

		// Does the update based on the incoming URI pattern
		switch (sUriMatcher.match(uri)) {

		// If the incoming URI matches the general logs pattern, does the
		// update based on
		// the incoming data.
		case LOGS:

			// Does the update and returns the number of rows updated.
			count = db.update(DownloadLog.Logs.TABLE_NAME, // The database table
															// name.
					values, // A map of column names and new values to use.
					where, // The where clause column names.
					whereArgs // The where clause column values to select on.
					);
			Log.d("COUNT_ IN UPDATE", "" + count);
			break;

		// If the incoming URI matches a single log ID, does the update based
		// on the incoming
		// data, but modifies the where clause to restrict it to the particular
		// log ID.
		case LOG_ID:
			// From the incoming URI, get the log ID
			String logId = uri.getPathSegments().get(
					DownloadLog.Logs.LOG_ID_PATH_POSITION);

			/*
			 * Starts creating the final WHERE clause by restricting it to the
			 * incoming log ID.
			 */
			finalWhere = DownloadLog.Logs._ID + // The ID column name
					" = " + // test for equality
					uri.getPathSegments(). // the incoming log ID
							get(DownloadLog.Logs.LOG_ID_PATH_POSITION);

			// If there were additional selection criteria, append them to the
			// final WHERE
			// clause
			if (where != null) {
				finalWhere = finalWhere + " AND " + where;
			}

			// Does the update and returns the number of rows updated.
			count = db.update(DownloadLog.Logs.TABLE_NAME, // The database table
															// name.
					values, // A map of column names and new values to use.
					finalWhere, // The final WHERE clause to use
								// placeholders for whereArgs
					whereArgs // The where clause column values to select on, or
								// null if the values are in the where argument.
					);
			break;
		// If the incoming pattern is invalid, throws an exception.
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}

		/*
		 * Gets a handle to the content resolver object for the current context,
		 * and notifies it that the incoming URI changed. The object passes this
		 * along to the resolver framework, and observers that have registered
		 * themselves for the provider are notified.
		 */
		getContext().getContentResolver().notifyChange(uri, null);

		// Returns the number of rows updated.
		return count;
	}

	/**
	 * A test package can call this to get a handle to the database underlying
	 * NotePadProvider, so it can insert test data into the database. The test
	 * case class is responsible for instantiating the provider in a test
	 * context; {@link android.test.ProviderTestCase2} does this during the call
	 * to setUp()
	 * 
	 * @return a handle to the database helper object for the provider's data.
	 */
	DatabaseHelper getOpenHelperForTest() {
		return mOpenHelper;
	}

}
